package com.fs.service;

import com.fs.entity.Role;
import com.fs.entity.User;
import com.fs.repository.RoleRepository;
import com.fs.repository.UserRepository;
import com.fs.service.bo.*;
import com.fs.service.bo.user.BoRoleInfo;
import com.fs.service.bo.user.BoSaveUser;
import com.fs.service.bo.user.BoUserInfo;
import com.fs.service.bo.user.BoUserInfoWithRole;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
@Validated
public class UserService {

    @PersistenceContext
    EntityManager entityManager;

    private final UserRepository userRepository;
    private final RoleRepository roleRepository;

    public UserService(UserRepository userRepository, RoleRepository roleRepository) {
        this.userRepository = userRepository;
        this.roleRepository = roleRepository;
    }

    @Transactional
    public void updateUserToken(@NotNull String token, @NotNull Integer userId) {
        User user = entityManager.find(User.class, userId);
        if (user == null) {
            throw new NotFoundException("没有找到用户");
        }
        user.setToken(token);
    }

    @Transactional
    public BoPageInfo<BoUserInfoWithRole> queryUserInfoWithRoleByPage(@NotNull BoUserInfo info, Integer pageNo, Integer pageSize) {
        Page<User> page = getUserByPage(info, pageNo, pageSize);
        BoPageInfo<BoUserInfoWithRole> pageInfo = new BoPageInfo<>();
        pageInfo.setResults(transformUserToUserInfoWithRole(page.getContent()));
        pageInfo.setTotal(page.getTotalElements());
        return pageInfo;
    }

    @Transactional
    public BoUserInfo saveUser(@Valid BoSaveUser param) {
        User user = new User();
        user.setName(param.getName());
        user.setLoginName(param.getLoginName());
        user.setPassword(param.getPassword());
        user = userRepository.save(user);
        return new BoUserInfo(user);
    }

    @Transactional
    public void deleteUser(Integer id) {
        userRepository.deleteById(id);
    }

    @Transactional
    public void addRoles(List<Integer> roleIDs, Integer UserID) {
        Optional<User> optUser = userRepository.findById(UserID);
        if(!optUser.isPresent()){
            throw new NotFoundException("没有找到用户");
        }

        User user =optUser.get();
        List<Role> roles = roleRepository.findAllById(roleIDs);
        user.getRoles().addAll(roles);
        userRepository.save(user);
    }


    @Transactional
    public @Nullable
    BoUserInfoWithRole getUserByLoginName(String loginName, String password) {
        User user = userRepository.findTop1ByLoginNameAndPassword(loginName, password);
        if (user == null) {
            return null;
        }
        BoUserInfoWithRole result = new BoUserInfoWithRole(user);
        user.getRoles().forEach(r -> result.getRoles().add(new BoRoleInfo(r)));
        return result;
    }


    private List<BoUserInfoWithRole> transformUserToUserInfoWithRole(List<User> users) {
        List<BoUserInfoWithRole> list = new ArrayList<>();
        for (User u : users) {
            BoUserInfoWithRole userInfoWithRole = new BoUserInfoWithRole(u);
            for (Role r : u.getRoles()) {
                userInfoWithRole.getRoles().add(new BoRoleInfo(r));
            }
            list.add(userInfoWithRole);
        }
        return list;
    }


    private Page<User> getUserByPage(BoUserInfo info, Integer pageNo, Integer pageSize) {
        Pageable pageable = PageRequest.of(--pageNo, pageSize, Sort.by(Sort.Direction.DESC, "id"));

        return userRepository.findAll((Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {

            List<Predicate> predicates = new ArrayList<Predicate>();
            if (StringUtils.hasLength(info.getName())) {
                predicates.add(cb.equal(root.get("name"), info.getName()));
            }
            if (StringUtils.hasLength(info.getLoginName())) {
                predicates.add(cb.equal(root.get("loginName"), info.getLoginName()));
            }
            int size = predicates.size();
            return query.where(predicates.toArray(new Predicate[size])).getRestriction();

        }, pageable);
    }


}
